package model

import (
	"fmt"
	"gowork/dormitoryManagementSystem/pool"
	"gowork/dormitoryManagementSystem/utils"
	"os"
	"sync"
	"time"
)

type CheckInInformation struct {
	Id int64 `xorm:"pk autoincr"`
	HandlingMethod int
	HouseholdId int64
	Name string
	Department string
	JobNo string
	CellPhoneNumber string
	Sex string
	CoHabitation bool
	CheckIn int64
	BuildingId int64
	AccommodationStandard int
	DateOfFirstResidence time.Time
	MonthlyOccupancyDate time.Time
 	AccommodationOffer int
	WaterAndElectricityDiscount int
	PublicWaterAndElectricityDiscount int
	GarbageFeeDiscount int
	Remarks string
	AccommodationDiscount int
	CheckOutDateOfThisMonth time.Time
	CheckOut int
	CreatedAt time.Time
	UpdatedAt time.Time
}

type MonthlyBuildingCost struct {
	Id int64 `xorm:"pk autoincr"`
	BuildingId int64
	YearMonth string
	Number int
	PublicUtilities float64
	PublicWaste float64
	ElectricityMeterOfLastMonth int
	ElectricityMeterOfThisMonth int
	WaterMeterOfLastMonth int
	WaterMeterOfThisMonth int
	MonthlyWaterAndElectricityCostList []*MonthlyWaterAndElectricityCost `xorm:"-"`
	PublicElectricityMeterOfLastMonth int
	PublicElectricityMeterOfThisMonth int
	PublicWaterMeterOfLastMonth int
	PublicWaterMeterOfThisMonth int
	CreatedAt time.Time
	UpdatedAt time.Time
}

type MonthlyWaterAndElectricityCost struct {
	Id int64 `xorm:"pk autoincr"`
	YearMonth string
	RoomId int64
	RoomNumber string
	BuildingId int64
	ElectricityMeterOfLastMonth int
	ElectricityMeterOfThisMonth int
	ElectricityConsumptionOfThisMonth int
	WaterMeterOfLastMonth int
	WaterMeterOfThisMonth int
	WaterConsumptionOfThisMonth int
	FeesPayableThisMonth float64
	CheckOutPayment float64
	ToBeCollected float64
	CreatedAt time.Time
	UpdatedAt time.Time
}

type RoomInfo struct {
	Id int64 `xorm:"pk autoincr"`
	Type int
	RoomNumber int
	BuildingId int64
	ResidentSum int
	ResidentNumber int
	ResidentSurplus int
	CurrentNumber int
	SumNumber int
	Full int
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ReportStatistics struct {
	Id int64 `xorm:"pk autoincr"`
	YearMonth string
	HandlingMethod int
	Name string
	Department string
	JobNo string
	CellPhoneNumber string
	Sex string
	CoHabitation bool
	CheckIn int64
	BuildingId int64
	AccommodationStandard int
	DateOfFirstResidence time.Time
	MonthlyOccupancyDate time.Time
	AccommodationOffer int
	WaterAndElectricityDiscount int
	PublicWaterAndElectricityDiscount int
	GarbageFeeDiscount int
	Remarks string
	RentOfThisMonth float64
	CheckOutDateOfThisMonth time.Time
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ExchangeHouses struct {
	Id int64 `xorm:"pk autoincr"`
	HouseholdId int64
	CheckInInformationId int64
	YearMonth string
	ExchangeTime time.Time
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Building struct {
	Id int64 `xorm:"pk autoincr"`
	Name string
	WaterPrice float64
	ElectricityPrice float64
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Statistics struct {
	BuildingName string
	BigBaySum int
	SingleRoomSum int
	TwoBedroomOneLiingSum int
	ThreeBedroomOneLiingSum int
	FourBedroomOneLiingSum int
	RoomSum int
	ResidentNumber int
	OccupancyRate float64
	WaterPrice float64
	ElectricityPrice float64
}

type CheckOutRecords struct {
	Id int64 `xorm:"pk autoincr"`
	YearMonth string
	BuildingId int64
	RoomInfoId int64
	Utilities float64
	PublicUtilities float64
	PublicGarbageFee float64
	Amount float64
	CreatedAt time.Time
	UpdatedAt time.Time
}

func GetMonth(m string) int{
	switch m {
	case "January":
		return 1
	case "February":
		return 2
	case "March":
		return 3
	case "April":
		return 4
	case "May":
		return 5
	case "June":
		return 6
	case "July":
		return 7
	case "August":
		return 8
	case "September":
		return 9
	case "October":
		return 10
	case "November":
		return 11
	case "December":
		return 12
	}
	return 0
}

func SubmitCostBuilding(mbcId int64, ym string, bId int64, mwaecList []*MonthlyWaterAndElectricityCost)(map[string]interface{}, error){

	var mbc MonthlyBuildingCost
	mbc.PublicWaterMeterOfThisMonth = mwaecList[len(mwaecList)-1].WaterConsumptionOfThisMonth
	mbc.PublicElectricityMeterOfThisMonth = mwaecList[len(mwaecList)-1].ElectricityConsumptionOfThisMonth
	mbc.WaterMeterOfThisMonth = mwaecList[len(mwaecList)-2].WaterMeterOfThisMonth
	mbc.ElectricityMeterOfThisMonth = mwaecList[len(mwaecList)-2].ElectricityMeterOfThisMonth
	mbc.PublicUtilities = float64(mwaecList[len(mwaecList)-1].FeesPayableThisMonth)
	x.Id(mbcId).Update(&mbc)
	//x.Where("building_id = ?",bId).And("year_month = ?", ym).Update(&mbc)

	for _, mwaec := range mwaecList[0:len(mwaecList)-3]{
		x.Id(mwaec.Id).Update(mwaec)
	}

	return map[string]interface{}{"code":200, "mesage":"成功"}, nil
}

func (cii *CheckInInformation)QueryCostBuilding(mbcId int64, bId int64, ym string)([]*MonthlyWaterAndElectricityCost, error){

	var mbc MonthlyBuildingCost
	x.Id(mbcId).Get(&mbc)
	//x.Where("building_id = ?",bId).And("year_month = ?", ym).Get(&mbc)

	var b Building
	x.Id(bId).Get(&b)

	var mwaecList []*MonthlyWaterAndElectricityCost
	x.Where("building_id = ?", bId).Find(&mwaecList)

	total := new(MonthlyWaterAndElectricityCost)
	total.RoomNumber = "合计"

	for _, mwaec := range mwaecList{

		sum, err := x.Where("room_info_id = ?", mwaec.RoomId).And("`year_month` = ?", ym).Sum(new(CheckOutRecords), "utilities")
		if err != nil{
			return nil, err
		}
		mwaec.CheckOutPayment = sum

		total.ElectricityMeterOfLastMonth += mwaec.ElectricityMeterOfLastMonth
		total.ElectricityMeterOfThisMonth += mwaec.ElectricityMeterOfThisMonth
		total.ElectricityConsumptionOfThisMonth += mwaec.ElectricityConsumptionOfThisMonth
		total.WaterMeterOfLastMonth += mwaec.WaterMeterOfLastMonth
		total.WaterMeterOfThisMonth += mwaec.WaterMeterOfThisMonth
		total.WaterConsumptionOfThisMonth += mwaec.WaterConsumptionOfThisMonth
		total.FeesPayableThisMonth += mwaec.FeesPayableThisMonth
		total.CheckOutPayment += mwaec.CheckOutPayment
		total.ToBeCollected += mwaec.CheckOutPayment + mwaec.FeesPayableThisMonth
	}
	mwaecList = append(mwaecList, total)

	var publicHydropower = MonthlyWaterAndElectricityCost{
		RoomNumber:                        "总水电表",
		ElectricityMeterOfLastMonth:       mbc.ElectricityMeterOfLastMonth,
		ElectricityMeterOfThisMonth:       mbc.ElectricityMeterOfThisMonth,
		ElectricityConsumptionOfThisMonth: mbc.ElectricityMeterOfThisMonth - mbc.ElectricityMeterOfLastMonth,
		WaterMeterOfLastMonth:             mbc.WaterMeterOfLastMonth,
		WaterMeterOfThisMonth:             mbc.WaterMeterOfThisMonth,
		WaterConsumptionOfThisMonth:       mbc.WaterMeterOfThisMonth - mbc.WaterMeterOfLastMonth,
		FeesPayableThisMonth:              float64(mbc.ElectricityMeterOfThisMonth)*b.ElectricityPrice + float64(mbc.WaterMeterOfThisMonth)*b.WaterPrice,
		CheckOutPayment:                   0,
		ToBeCollected:                     float64(mbc.ElectricityMeterOfThisMonth)*b.ElectricityPrice + float64(mbc.WaterMeterOfThisMonth)*b.WaterPrice,
	}
	mwaecList = append(mwaecList, &publicHydropower)

	publicSum, err := x.Where("building_id = ?", b.Id).And("`year_month` = ?", ym).Sum(new(CheckOutRecords), "public_utilities")
	if err != nil{
		return nil, err
	}
	var totalWaterMeter = MonthlyWaterAndElectricityCost{
		RoomNumber:                        "公共水电",
		ElectricityMeterOfLastMonth:       0,
		ElectricityMeterOfThisMonth:       0,
		ElectricityConsumptionOfThisMonth: mbc.PublicElectricityMeterOfThisMonth,
		WaterMeterOfLastMonth:             0,
		WaterMeterOfThisMonth:             0,
		WaterConsumptionOfThisMonth:       mbc.PublicWaterMeterOfThisMonth,
		FeesPayableThisMonth:              mbc.PublicUtilities,
		CheckOutPayment:                   publicSum,
		ToBeCollected:                     mbc.PublicUtilities - publicSum,
	}
	mwaecList = append(mwaecList, &totalWaterMeter)

	return mwaecList, nil
}

func GetCount(year int, month int) (days int) {
	if month != 2 {
		if month == 4 || month == 6 || month == 9 || month == 11 {
			days = 3
		} else {
			days = 31
			fmt.Fprintln(os.Stdout, "The month has 31 days");
		}
	} else {
		if (((year % 4) == 0 && (year % 100) != 0) || (year % 400) == 0) {
			days = 29
		} else {
			days = 28
		}
	}
	fmt.Fprintf(os.Stdout, "The %d-%d has %d days.\n", year, month, days)
	return
}

func SubMonth(t1, t2 time.Time) (month int) {
	y1 := t1.Year()
	y2 := t2.Year()
	m1 := int(t1.Month())
	m2 := int(t2.Month())
	d1 := t1.Day()
	d2 := t2.Day()

	yearInterval := y1 - y2
	// 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
	if m1 < m2 || m1 == m2 && d1 < d2 {
		yearInterval--
	}
	// 获取月数差值
	monthInterval := (m1 + 12) - m2
	if d1 < d2 {
		monthInterval--
	}
	monthInterval %= 12
	month = yearInterval*12 + monthInterval
	return
}

func QueryRoom()([]*RoomInfo, error){

	var riList []*RoomInfo
	x.Join("INNER", "check_in_information", "check_in_information.check_in_id = room_info.id").
		Where("check_in_information.co_habitation = ?", false).
		Find(&riList)

	var friList []*RoomInfo
	x.Where("full = ?", false).
		Find(&friList)

	for _, fri := range friList{
		riList = append(riList, fri)
	}

	return riList, nil
}

func QueryCurrentMonthBuilding(ym string)([]*MonthlyBuildingCost, error){

	var mbcList []*MonthlyBuildingCost
	x.Where("year_month = ?", ym).Find(&mbcList)
	return mbcList, nil
}

func QueryCurrentMonthRoom(ym string, bId int64)([]*MonthlyWaterAndElectricityCost, error){

	var mwecList []*MonthlyWaterAndElectricityCost
	x.Where("year_month = ?", ym).And("building_id = ?", bId).Find(&mwecList)
	return mwecList, nil
}

func(eh *ExchangeHouses)Exchange(ciiId int64, ciId int64, bId int64){

	w := new(utils.Worker)

	var cii CheckInInformation
	x.Where("id = ? ", ciiId).Get(&cii)

	var ehv = ExchangeHouses{
		Id:                   w.GetId(),
		HouseholdId:          cii.HouseholdId,
		CheckInInformationId: cii.Id,
		YearMonth:            time.Now().Format("2006-01"),
		ExchangeTime:         time.Now(),
		CreatedAt:            time.Now(),
		UpdatedAt:            time.Now(),
	}
	x.Insert(&ehv)

	var newCii = CheckInInformation{
		Id:                                w.GetId(),
		HouseholdId:                       cii.HouseholdId,
		CheckIn:                           ciId,
		BuildingId:                        bId,
		DateOfFirstResidence:              cii.DateOfFirstResidence,
		MonthlyOccupancyDate:              time.Now(),
		AccommodationDiscount:			   cii.AccommodationDiscount,
	}
	x.Insert(&newCii)

	cii.CheckOutDateOfThisMonth = time.Now()
	x.Id(cii.Id).Update(&cii)
}

var lock sync.Mutex

func(eh *ExchangeHouses)ExchangeLock(ciiId int64, ciId int64, bId int64) (map[string]interface{}, error){

	lock.Lock()

	var room RoomInfo
	x.Id(ciId).Get(&room)
	if room.Full == 2{
		lock.Unlock()

		return map[string]interface{}{"message":"该房间已满", "code":200}, nil
	}

	w := new(utils.Worker)

	var cii CheckInInformation
	x.Where("id = ? ", ciiId).Get(&cii)

	var ehv = ExchangeHouses{
		Id:                   w.GetId(),
		HouseholdId:          cii.HouseholdId,
		CheckInInformationId: cii.Id,
		YearMonth:            time.Now().Format("2006-01"),
		ExchangeTime:         time.Now(),
		CreatedAt:            time.Now(),
		UpdatedAt:            time.Now(),
	}
	x.Insert(&ehv)

	var newCii = CheckInInformation{
		Id:                                w.GetId(),
		HouseholdId:                       cii.HouseholdId,
		CheckIn:                           ciId,
		BuildingId:                        bId,
		DateOfFirstResidence:              cii.DateOfFirstResidence,
		MonthlyOccupancyDate:              time.Now(),
		AccommodationDiscount:          cii.AccommodationDiscount,
	}
	x.Insert(&newCii)

	cii.CheckOutDateOfThisMonth = time.Now()
	x.Id(cii.Id).Update(&cii)

	if room.CurrentNumber + 1  >= room.SumNumber{
		room.Full = 2
	}

	room.CurrentNumber += 1
	x.Id(room.Id).Update(&room)

	lock.Unlock()

	return map[string]interface{}{"message":"更换成功", "code":200}, nil
}

func (cii *CheckInInformation)CalculateRent()(map[string]interface{}, error){

	w := new(utils.Worker)

	var mbcList []*MonthlyBuildingCost
	x.Where("`year_month` = ?", time.Now().Format("2006-01")).Find(&mbcList)
	fmt.Println("mbcList：", mbcList)

	for _, mbcv := range mbcList {

		var ciis []*CheckInInformation
		x.Where("building_id = ? ", mbcv.BuildingId).And("check_out = ?", 1).Find(&ciis)
		fmt.Println("ciis：", ciis)

		lastMonth := time.Now()
		count := GetCount(lastMonth.Year(), GetMonth(lastMonth.Month().String()))
		fmt.Println("count：", count)

		var sumDay int
		for _, ciivDay := range ciis {
			var eh ExchangeHouses
			x.Where("check_in_information_id = ?", ciivDay.Id).And("`year_month` = ?", time.Now().Format("2006-01")).Get(&eh)
			fmt.Println("eh：", eh)
			if eh.Id != 0{
				sumDay += int(ciivDay.CheckOutDateOfThisMonth.Sub(ciivDay.MonthlyOccupancyDate).Hours()/24)
			}else {
				sumDay += int(time.Now().Sub(ciivDay.MonthlyOccupancyDate).Hours() / 24)
			}
		}
		fmt.Println("sumDay：", sumDay)

		var mwaecList []*MonthlyWaterAndElectricityCost
		x.Where("building_id = ? ", mbcv.BuildingId).And("`year_month` = ?", time.Now().Format("2006-01")).Find(&mwaecList)
		fmt.Println("mwaecList：", mwaecList)
		for _, mwaec := range mwaecList {

			fmt.Println("旧mbcv.PublicUtilities：", mbcv.PublicUtilities)
			fmt.Println("旧mbcv.PublicWaste：", mbcv.PublicWaste)
			fmt.Println("旧mwaec.FeesPayableThisMonth：", mwaec.FeesPayableThisMonth)

			var corList []*CheckOutRecords
			x.Where("room_info_id = ? ", mwaec.RoomId).And("`year_month` = ?", time.Now().Format("2006-01")).Find(&corList)
			fmt.Println("corList：", corList)
			for _, cor := range corList{

				fmt.Println("cor.PublicUtilities：", cor.PublicUtilities)
				fmt.Println("cor.PublicGarbageFee：", cor.PublicGarbageFee)
				fmt.Println("cor.Utilities：", cor.Utilities)

				mbcv.PublicUtilities -= cor.PublicUtilities
				mbcv.PublicWaste -= cor.PublicGarbageFee
				mwaec.FeesPayableThisMonth -= cor.Utilities
			}

			fmt.Println("新mbcv.PublicUtilities：", mbcv.PublicUtilities)
			fmt.Println("新mbcv.PublicWaste：", mbcv.PublicWaste)
			fmt.Println("新mwaec.FeesPayableThisMonth：", mwaec.FeesPayableThisMonth)

			var ciiList []*CheckInInformation
			x.Where("check_in = ?", mwaec.RoomId).And("check_out = ?", 1).Find(&ciiList)
			fmt.Println("ciiList：", ciiList)

			var weSumDay int
			for _, weCiivDay := range ciiList {
				var eh ExchangeHouses
				x.Where("check_in_information_id = ?", weCiivDay.Id).And("`year_month` = ?", time.Now().Format("2006-01")).Get(&eh)
				if eh.Id != 0{
					weSumDay += int(weCiivDay.CheckOutDateOfThisMonth.Sub(weCiivDay.MonthlyOccupancyDate).Hours()/24)
				}else {
					weSumDay += int(time.Now().Sub(weCiivDay.MonthlyOccupancyDate).Hours() / 24)
				}
			}
			fmt.Println("weSumDay：", weSumDay)

			for _, ciiv := range ciiList {

				var ceh ExchangeHouses
				x.Where("check_in_information_id = ?", ciiv.Id).And("`year_month` = ?", time.Now().Format("2006-01")).Get(&ceh)
				fmt.Println("ceh：", ceh)

				var checkOutDate time.Time
				if ceh.Id != 0 {
					checkOutDate = ciiv.CheckOutDateOfThisMonth

					ciiv.CheckOut = 2
					x.Id(ciiv.Id).Update(&ciiv)
				} else {
					checkOutDate = time.Now()
				}

				var rent float64

				CheckInDays := int(checkOutDate.Sub(ciiv.MonthlyOccupancyDate).Hours() / 24)
				fmt.Println("CheckInDays：", CheckInDays)

				fmt.Println("AccommodationStandard：", ciiv.AccommodationStandard)
				as := float64(ciiv.AccommodationOffer/count*CheckInDays)
				fmt.Println("as：", as)
				rent = float64(mwaec.FeesPayableThisMonth)/float64(weSumDay)*float64(CheckInDays)*float64(ciiv.WaterAndElectricityDiscount/100) + as
				fmt.Println("rent1：", rent)

				fmt.Println("mbcv.PublicUtilities：", mbcv.PublicUtilities)
				fmt.Println("mbcv.PublicWaste：", mbcv.PublicWaste)
				rent += mbcv.PublicUtilities/float64(sumDay)*float64(CheckInDays)*float64(ciiv.PublicWaterAndElectricityDiscount/100) + mbcv.PublicWaste/float64(sumDay)*float64(CheckInDays)*float64(ciiv.GarbageFeeDiscount/100)

				switch ciiv.AccommodationDiscount {
				case 1:
					rent -= as
				case 2:
					rent -= as
				case 3:

					if SubMonth(checkOutDate, ciiv.DateOfFirstResidence) <= 3 {
						rent -= 150
					} else {

						beOverdueTime := ciiv.DateOfFirstResidence.AddDate(0, 3, 0)
						DiscountDay := beOverdueTime.Sub(ciiv.DateOfFirstResidence).Hours() / 24

						if beOverdueTime.After(ciiv.MonthlyOccupancyDate) == true && beOverdueTime.Before(checkOutDate) == true {

							rent -= float64(beOverdueTime.Sub(ciiv.MonthlyOccupancyDate).Hours()/24) * 150 / DiscountDay
						}
					}
				case 4:
					rent -= 150
				case 5:
					if SubMonth(checkOutDate, ciiv.DateOfFirstResidence) <= 3 {
						rent -= 210
					} else {

						beOverdueTime := ciiv.DateOfFirstResidence.AddDate(0, 3, 0)
						DiscountDay := beOverdueTime.Sub(ciiv.DateOfFirstResidence).Hours() / 24

						if beOverdueTime.After(ciiv.MonthlyOccupancyDate) == true && beOverdueTime.Before(checkOutDate) == true {

							rent -= float64(beOverdueTime.Sub(ciiv.MonthlyOccupancyDate).Hours()/24) * 210 / DiscountDay
						}
					}
				case 6:
					rent -= 210
				}

				var rs = ReportStatistics{
					Id:                                w.GetId(),
					YearMonth:                         time.Now().Format("2006-01"),
					HandlingMethod:                    ciiv.HandlingMethod,
					Name:                              ciiv.Name,
					Department:                        ciiv.Department,
					JobNo:                             ciiv.JobNo,
					CellPhoneNumber:                   ciiv.CellPhoneNumber,
					Sex:                               ciiv.Sex,
					CoHabitation:                      ciiv.CoHabitation,
					CheckIn:                           ciiv.CheckIn,
					BuildingId:                        ciiv.BuildingId,
					AccommodationStandard:             ciiv.AccommodationDiscount,
					DateOfFirstResidence:              ciiv.DateOfFirstResidence,
					MonthlyOccupancyDate:              ciiv.MonthlyOccupancyDate,
					AccommodationOffer:                ciiv.AccommodationOffer,
					WaterAndElectricityDiscount:       ciiv.WaterAndElectricityDiscount,
					PublicWaterAndElectricityDiscount: ciiv.PublicWaterAndElectricityDiscount,
					GarbageFeeDiscount:                ciiv.GarbageFeeDiscount,
					Remarks:                           ciiv.Remarks,
					RentOfThisMonth:                   rent,
					CheckOutDateOfThisMonth:           time.Now(),
					CreatedAt:                         time.Now(),
					UpdatedAt:                         time.Now(),
				}

				x.Insert(&rs)

				ciiv.MonthlyOccupancyDate = time.Now().AddDate(0, 1, -time.Now().Day()+1)
				x.Id(ciiv.Id).Update(ciiv)
			}

			var newMwaec = MonthlyWaterAndElectricityCost{
				Id:                                w.GetId(),
				YearMonth:                         time.Now().AddDate(0, 1,0).Format("2006-01"),
				RoomId:                            mwaec.RoomId,
				RoomNumber:                        mwaec.RoomNumber,
				BuildingId:                        mwaec.BuildingId,
				ElectricityMeterOfLastMonth:       mwaec.ElectricityMeterOfThisMonth,
				ElectricityMeterOfThisMonth:       0,
				ElectricityConsumptionOfThisMonth: 0,
				WaterMeterOfLastMonth:             mwaec.WaterMeterOfThisMonth,
				WaterMeterOfThisMonth:             0,
				WaterConsumptionOfThisMonth:       0,
				FeesPayableThisMonth:              0,
				CheckOutPayment:                   0,
				ToBeCollected:                     0,
				CreatedAt:                         time.Now(),
				UpdatedAt:                         time.Now(),
			}

			x.Insert(&newMwaec)

		}
		var newMbc = MonthlyBuildingCost{
			Id:                                 w.GetId(),
			BuildingId:                         mbcv.BuildingId,
			YearMonth:                          time.Now().AddDate(0, 1,0).Format("2006-01"),
			Number:                             mbcv.Number,
			PublicUtilities:                    0,
			PublicWaste:                        0,
			ElectricityMeterOfLastMonth:        mbcv.ElectricityMeterOfThisMonth,
			ElectricityMeterOfThisMonth:        0,
			WaterMeterOfLastMonth:              mbcv.WaterMeterOfThisMonth,
			WaterMeterOfThisMonth:              0,
			MonthlyWaterAndElectricityCostList: nil,
			PublicElectricityMeterOfLastMonth:  mbcv.PublicElectricityMeterOfThisMonth,
			PublicElectricityMeterOfThisMonth:  0,
			PublicWaterMeterOfLastMonth:        mbcv.PublicWaterMeterOfThisMonth,
			PublicWaterMeterOfThisMonth:        0,
			CreatedAt:                          time.Now(),
			UpdatedAt:                          time.Now(),
		}

		x.Insert(&newMbc)
	}

	return map[string]interface{}{"code":200, "message":"成功"}, nil
}

func (cii *CheckInInformation)CalculateRentAsync()(map[string]interface{}, error){

	w := new(utils.Worker)

	p := pool.NewSimplePoll(3)
	for i := 0; i < 3; i++ {
		var finalI int = i
		p.Add(func() {
			var mbcList []*MonthlyBuildingCost
			x.Where("`year_month` = ?", time.Now().Format("2006-01")).Limit(3, finalI * 3).Find(&mbcList)
			fmt.Println("mbcList：", mbcList)

			for _, mbcv := range mbcList {

				var ciis []*CheckInInformation
				x.Where("building_id = ? ", mbcv.BuildingId).And("check_out = ?", 1).Find(&ciis)
				fmt.Println("ciis：", ciis)

				lastMonth := time.Now()
				count := GetCount(lastMonth.Year(), GetMonth(lastMonth.Month().String()))
				fmt.Println("count：", count)

				var sumDay int
				for _, ciivDay := range ciis {
					var eh ExchangeHouses
					x.Where("check_in_information_id = ?", ciivDay.Id).And("`year_month` = ?", time.Now().Format("2006-01")).Get(&eh)
					fmt.Println("eh：", eh)
					if eh.Id != 0{
						sumDay += int(ciivDay.CheckOutDateOfThisMonth.Sub(ciivDay.MonthlyOccupancyDate).Hours()/24)
					}else {
						sumDay += int(time.Now().Sub(ciivDay.MonthlyOccupancyDate).Hours() / 24)
					}
				}
				fmt.Println("sumDay：", sumDay)

				var mwaecList []*MonthlyWaterAndElectricityCost
				x.Where("building_id = ? ", mbcv.BuildingId).And("`year_month` = ?", time.Now().Format("2006-01")).Find(&mwaecList)
				fmt.Println("mwaecList：", mwaecList)
				for _, mwaec := range mwaecList {

					fmt.Println("旧mbcv.PublicUtilities：", mbcv.PublicUtilities)
					fmt.Println("旧mbcv.PublicWaste：", mbcv.PublicWaste)
					fmt.Println("旧mwaec.FeesPayableThisMonth：", mwaec.FeesPayableThisMonth)

					var corList []*CheckOutRecords
					x.Where("room_info_id = ? ", mwaec.RoomId).And("`year_month` = ?", time.Now().Format("2006-01")).Find(&corList)
					fmt.Println("corList：", corList)
					for _, cor := range corList{

						fmt.Println("cor.PublicUtilities：", cor.PublicUtilities)
						fmt.Println("cor.PublicGarbageFee：", cor.PublicGarbageFee)
						fmt.Println("cor.Utilities：", cor.Utilities)

						mbcv.PublicUtilities -= cor.PublicUtilities
						mbcv.PublicWaste -= cor.PublicGarbageFee
						mwaec.FeesPayableThisMonth -= cor.Utilities
					}

					fmt.Println("新mbcv.PublicUtilities：", mbcv.PublicUtilities)
					fmt.Println("新mbcv.PublicWaste：", mbcv.PublicWaste)
					fmt.Println("新mwaec.FeesPayableThisMonth：", mwaec.FeesPayableThisMonth)

					var ciiList []*CheckInInformation
					x.Where("check_in = ?", mwaec.RoomId).And("check_out = ?", 1).Find(&ciiList)
					fmt.Println("ciiList：", ciiList)

					var weSumDay int
					for _, weCiivDay := range ciiList {
						var eh ExchangeHouses
						x.Where("check_in_information_id = ?", weCiivDay.Id).And("`year_month` = ?", time.Now().Format("2006-01")).Get(&eh)
						if eh.Id != 0{
							weSumDay += int(weCiivDay.CheckOutDateOfThisMonth.Sub(weCiivDay.MonthlyOccupancyDate).Hours()/24)
						}else {
							weSumDay += int(time.Now().Sub(weCiivDay.MonthlyOccupancyDate).Hours() / 24)
						}
					}
					fmt.Println("weSumDay：", weSumDay)

					for _, ciiv := range ciiList {

						var ceh ExchangeHouses
						x.Where("check_in_information_id = ?", ciiv.Id).And("`year_month` = ?", time.Now().Format("2006-01")).Get(&ceh)
						fmt.Println("ceh：", ceh)

						var checkOutDate time.Time
						if ceh.Id != 0 {
							checkOutDate = ciiv.CheckOutDateOfThisMonth

							ciiv.CheckOut = 2
							x.Id(ciiv.Id).Update(&ciiv)
						} else {
							checkOutDate = time.Now()
						}

						var rent float64

						CheckInDays := int(checkOutDate.Sub(ciiv.MonthlyOccupancyDate).Hours() / 24)
						fmt.Println("CheckInDays：", CheckInDays)

						fmt.Println("AccommodationStandard：", ciiv.AccommodationStandard)
						as := float64(ciiv.AccommodationOffer/count*CheckInDays)
						fmt.Println("as：", as)
						rent = float64(mwaec.FeesPayableThisMonth)/float64(weSumDay)*float64(CheckInDays)*float64(ciiv.WaterAndElectricityDiscount/100) + as
						fmt.Println("rent1：", rent)

						fmt.Println("mbcv.PublicUtilities：", mbcv.PublicUtilities)
						fmt.Println("mbcv.PublicWaste：", mbcv.PublicWaste)
						rent += mbcv.PublicUtilities/float64(sumDay)*float64(CheckInDays)*float64(ciiv.PublicWaterAndElectricityDiscount/100) + mbcv.PublicWaste/float64(sumDay)*float64(CheckInDays)*float64(ciiv.GarbageFeeDiscount/100)

						switch ciiv.AccommodationDiscount {
						case 1:
							rent -= as
						case 2:
							rent -= as
						case 3:

							if SubMonth(checkOutDate, ciiv.DateOfFirstResidence) <= 3 {
								rent -= 150
							} else {

								beOverdueTime := ciiv.DateOfFirstResidence.AddDate(0, 3, 0)
								DiscountDay := beOverdueTime.Sub(ciiv.DateOfFirstResidence).Hours() / 24

								if beOverdueTime.After(ciiv.MonthlyOccupancyDate) == true && beOverdueTime.Before(checkOutDate) == true {

									rent -= float64(beOverdueTime.Sub(ciiv.MonthlyOccupancyDate).Hours()/24) * 150 / DiscountDay
								}
							}
						case 4:
							rent -= 150
						case 5:
							if SubMonth(checkOutDate, ciiv.DateOfFirstResidence) <= 3 {
								rent -= 210
							} else {

								beOverdueTime := ciiv.DateOfFirstResidence.AddDate(0, 3, 0)
								DiscountDay := beOverdueTime.Sub(ciiv.DateOfFirstResidence).Hours() / 24

								if beOverdueTime.After(ciiv.MonthlyOccupancyDate) == true && beOverdueTime.Before(checkOutDate) == true {

									rent -= float64(beOverdueTime.Sub(ciiv.MonthlyOccupancyDate).Hours()/24) * 210 / DiscountDay
								}
							}
						case 6:
							rent -= 210
						}

						var rs = ReportStatistics{
							Id:                                w.GetId(),
							YearMonth:                         time.Now().Format("2006-01"),
							HandlingMethod:                    ciiv.HandlingMethod,
							Name:                              ciiv.Name,
							Department:                        ciiv.Department,
							JobNo:                             ciiv.JobNo,
							CellPhoneNumber:                   ciiv.CellPhoneNumber,
							Sex:                               ciiv.Sex,
							CoHabitation:                      ciiv.CoHabitation,
							CheckIn:                           ciiv.CheckIn,
							BuildingId:                        ciiv.BuildingId,
							AccommodationStandard:             ciiv.AccommodationDiscount,
							DateOfFirstResidence:              ciiv.DateOfFirstResidence,
							MonthlyOccupancyDate:              ciiv.MonthlyOccupancyDate,
							AccommodationOffer:                ciiv.AccommodationOffer,
							WaterAndElectricityDiscount:       ciiv.WaterAndElectricityDiscount,
							PublicWaterAndElectricityDiscount: ciiv.PublicWaterAndElectricityDiscount,
							GarbageFeeDiscount:                ciiv.GarbageFeeDiscount,
							Remarks:                           ciiv.Remarks,
							RentOfThisMonth:                   rent,
							CheckOutDateOfThisMonth:           time.Now(),
							CreatedAt:                         time.Now(),
							UpdatedAt:                         time.Now(),
						}

						x.Insert(&rs)

						ciiv.MonthlyOccupancyDate = time.Now().AddDate(0, 1, -time.Now().Day()+1)
						x.Id(ciiv.Id).Update(ciiv)
					}

					var newMwaec = MonthlyWaterAndElectricityCost{
						Id:                                w.GetId(),
						YearMonth:                         time.Now().AddDate(0, 1,0).Format("2006-01"),
						RoomId:                            mwaec.RoomId,
						RoomNumber:                        mwaec.RoomNumber,
						BuildingId:                        mwaec.BuildingId,
						ElectricityMeterOfLastMonth:       mwaec.ElectricityMeterOfThisMonth,
						ElectricityMeterOfThisMonth:       0,
						ElectricityConsumptionOfThisMonth: 0,
						WaterMeterOfLastMonth:             mwaec.WaterMeterOfThisMonth,
						WaterMeterOfThisMonth:             0,
						WaterConsumptionOfThisMonth:       0,
						FeesPayableThisMonth:              0,
						CheckOutPayment:                   0,
						ToBeCollected:                     0,
						CreatedAt:                         time.Now(),
						UpdatedAt:                         time.Now(),
					}

					x.Insert(&newMwaec)

				}
				var newMbc = MonthlyBuildingCost{
					Id:                                 w.GetId(),
					BuildingId:                         mbcv.BuildingId,
					YearMonth:                          time.Now().AddDate(0, 1,0).Format("2006-01"),
					Number:                             mbcv.Number,
					PublicUtilities:                    0,
					PublicWaste:                        0,
					ElectricityMeterOfLastMonth:        mbcv.ElectricityMeterOfThisMonth,
					ElectricityMeterOfThisMonth:        0,
					WaterMeterOfLastMonth:              mbcv.WaterMeterOfThisMonth,
					WaterMeterOfThisMonth:              0,
					MonthlyWaterAndElectricityCostList: nil,
					PublicElectricityMeterOfLastMonth:  mbcv.PublicElectricityMeterOfThisMonth,
					PublicElectricityMeterOfThisMonth:  0,
					PublicWaterMeterOfLastMonth:        mbcv.PublicWaterMeterOfThisMonth,
					PublicWaterMeterOfThisMonth:        0,
					CreatedAt:                          time.Now(),
					UpdatedAt:                          time.Now(),
				}

				x.Insert(&newMbc)
			}
		})
	}
	p.Run()

	return map[string]interface{}{"code":200, "message":"成功"}, nil
}

func (cii *CheckInInformation)BuildingStatistics()([]*Statistics, error){

	var sList []*Statistics

	var bList []*Building
	x.Find(&bList)

	for _, b := range bList{

		var s Statistics
		s.BuildingName = b.Name

		bigBaySum , err := x.Where("building_id = ?", b.Id).And("`type` = ?", 1).Count(new(RoomInfo))
		if err != nil{
			return nil, err
		}
		s.BigBaySum = int(bigBaySum)

		singleRoomSum , err := x.Where("building_id = ?", b.Id).And("`type` = ?", 2).Count(new(RoomInfo))
		if err != nil{
			return nil, err
		}
		s.SingleRoomSum = int(singleRoomSum)

		twoBedroomOneLiingSum , err := x.Where("building_id = ?", b.Id).And("`type` = ?", 3).Count(new(RoomInfo))
		if err != nil{
			return nil, err
		}
		s.TwoBedroomOneLiingSum = int(twoBedroomOneLiingSum)

		threeBedroomOneLiingSum , err := x.Where("building_id = ?", b.Id).And("`type` = ?", 4).Count(new(RoomInfo))
		if err != nil{
			return nil, err
		}
		s.ThreeBedroomOneLiingSum = int(threeBedroomOneLiingSum)

		fourBedroomOneLiingSum , err := x.Where("building_id = ?", b.Id).And("`type` = ?", 5).Count(new(RoomInfo))
		if err != nil{
			return nil, err
		}
		s.FourBedroomOneLiingSum = int(fourBedroomOneLiingSum)

		roomSum , err := x.Where("building_id = ?", b.Id).Count(new(RoomInfo))
		if err != nil{
			return nil, err
		}
		s.RoomSum = int(roomSum)

		residentNumber, err := x.Where("building_id = ?", b.Id).Sum(new(RoomInfo),"resident_sum")
		s.ResidentNumber = int(residentNumber)

		number, err := x.Where("building_id = ?", b.Id).Sum(new(RoomInfo),"resident_number")
		if s.ResidentNumber == 0{
			s.OccupancyRate = 0
		}else {
			s.OccupancyRate = number / float64(s.ResidentNumber)
		}

		s.WaterPrice = b.WaterPrice
		s.ElectricityPrice = b.ElectricityPrice

		sList = append(sList, &s)
	}

	return sList, nil
}

func QueryReportStatistics(d string)([]*ReportStatistics, error){

	var rsList []*ReportStatistics
	x.Where("year_month = ?", d).Find(&rsList)

	return rsList, nil
}